#pragma once

#include <thread>
#include <memory>
#include <zmqpp/zmqpp.hpp>
#include "base/Logger.h"
#include "utils/utils.h"
#include "connection/ZmqConnection.h"

using namespace zmqpp;

// TODO: AbstractNode的子类是消息模型与网络协议耦合的, 后续考虑将消息模型与网络协议解耦合, 以实现zeroplusmq支持多种支持消息订阅机制的网络协议通信, 如dds、someip
namespace zeroplus::mq
{
    using sockType = zmqpp::socket_type;
    using ZmqConnectionPtr = std::unique_ptr<ZmqConnection>;
    using OnMsgRecvCb = std::function<void(const Bytes &)>;

    enum ConnectType
    {
        bind,
        connect
    };

    class AbstractNode
    {
    public:
        bool stop_;
        ConnectType connectType_;
        std::string uri_;
        ZmqConnectionPtr conn_;

    protected:
        inline void CreateConnection(const zmqpp::socket_type &socketType, std::string uri, const ConnectType &connectType)
        {
            connectType_ = connectType;
            uri_ = uri;
            conn_ = std::make_unique<ZmqConnection>(socketType, uri_);
            try
            {
                switch (connectType_)
                {
                case bind:
                    conn_->Bind();
                    LOG_INFO("Binding to %s", uri_.c_str());
                    break;
                case connect:
                    conn_->Connect();
                    LOG_INFO("Connecting to %s", uri_.c_str());
                default:
                    break;
                }
            }
            catch (const zmqpp::exception &ex)
            {
                LOG_ERROR("failed to init");
                LOG_ERROR("Exception: %s", ex.what());
            }
        }

    public:
        AbstractNode()
            : stop_(false)
        {
        }

        ~AbstractNode()
        {
            switch (connectType_)
            {
            case bind:
                conn_->UnBind();
                break;
            case connect:
                conn_->DisConnect();
            default:
                break;
            }
        }

        zmqpp::socket_t *GetSocket()
        {
            return conn_->GetSocket();
        }

        
    };

}
